{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# pytorch 的学习\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 读取数据\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-05-30T01:43:43.322025Z",
     "start_time": "2023-05-30T01:43:42.688666Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "torch version is  1.12.1+cu113 and cuda  available is True\n"
     ]
    }
   ],
   "source": [
    "from torch.utils.data import Dataset  # 导入数据集处理基类\n",
    "from PIL import Image                 # 图片处理\n",
    "import os\n",
    "import torch\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "\n",
    "print(\"torch version is \", torch.__version__,\n",
    "      \"and cuda  available is\", torch.cuda.is_available())\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-05-30T01:43:43.325891Z",
     "start_time": "2023-05-30T01:43:43.322959Z"
    },
    "collapsed": true,
    "jupyter": {
     "outputs_hidden": true
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Help on class Dataset in module torch.utils.data.dataset:\n",
      "\n",
      "class Dataset(typing.Generic)\n",
      " |  Dataset(*args, **kwds)\n",
      " |  \n",
      " |  An abstract class representing a :class:`Dataset`.\n",
      " |  \n",
      " |  All datasets that represent a map from keys to data samples should subclass\n",
      " |  it. All subclasses should overwrite :meth:`__getitem__`, supporting fetching a\n",
      " |  data sample for a given key. Subclasses could also optionally overwrite\n",
      " |  :meth:`__len__`, which is expected to return the size of the dataset by many\n",
      " |  :class:`~torch.utils.data.Sampler` implementations and the default options\n",
      " |  of :class:`~torch.utils.data.DataLoader`.\n",
      " |  \n",
      " |  .. note::\n",
      " |    :class:`~torch.utils.data.DataLoader` by default constructs a index\n",
      " |    sampler that yields integral indices.  To make it work with a map-style\n",
      " |    dataset with non-integral indices/keys, a custom sampler must be provided.\n",
      " |  \n",
      " |  Method resolution order:\n",
      " |      Dataset\n",
      " |      typing.Generic\n",
      " |      builtins.object\n",
      " |  \n",
      " |  Methods defined here:\n",
      " |  \n",
      " |  __add__(self, other: 'Dataset[T_co]') -> 'ConcatDataset[T_co]'\n",
      " |  \n",
      " |  __getitem__(self, index) -> +T_co\n",
      " |  \n",
      " |  ----------------------------------------------------------------------\n",
      " |  Data descriptors defined here:\n",
      " |  \n",
      " |  __dict__\n",
      " |      dictionary for instance variables (if defined)\n",
      " |  \n",
      " |  __weakref__\n",
      " |      list of weak references to the object (if defined)\n",
      " |  \n",
      " |  ----------------------------------------------------------------------\n",
      " |  Data and other attributes defined here:\n",
      " |  \n",
      " |  __orig_bases__ = (typing.Generic[+T_co],)\n",
      " |  \n",
      " |  __parameters__ = (+T_co,)\n",
      " |  \n",
      " |  ----------------------------------------------------------------------\n",
      " |  Class methods inherited from typing.Generic:\n",
      " |  \n",
      " |  __class_getitem__(params) from builtins.type\n",
      " |  \n",
      " |  __init_subclass__(*args, **kwargs) from builtins.type\n",
      " |      This method is called when a class is subclassed.\n",
      " |      \n",
      " |      The default implementation does nothing. It may be\n",
      " |      overridden to extend subclasses.\n",
      " |  \n",
      " |  ----------------------------------------------------------------------\n",
      " |  Static methods inherited from typing.Generic:\n",
      " |  \n",
      " |  __new__(cls, *args, **kwds)\n",
      " |      Create and return a new object.  See help(type) for accurate signature.\n",
      "\n"
     ]
    }
   ],
   "source": [
    "help(Dataset)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-05-30T01:43:43.328451Z",
     "start_time": "2023-05-30T01:43:43.327172Z"
    }
   },
   "outputs": [],
   "source": [
    "dir_path = \"dataset/hymenoptera_data/train/ants\"\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-05-30T01:43:43.331975Z",
     "start_time": "2023-05-30T01:43:43.329196Z"
    }
   },
   "outputs": [],
   "source": [
    "# 定义自己的数据类\n",
    "class MyData(Dataset):\n",
    "    def __init__(self, root_dir, label_dir):\n",
    "        # 初始化路径配置\n",
    "        self.root_dir = root_dir   # 跟路径\n",
    "        self.label_dir = label_dir  # 数据集路径\n",
    "        self.path = os.path.join(self.root_dir, self.label_dir)\n",
    "        self.img_path = os.listdir(self.path)  # 查找所有数据集文件名称\n",
    "\n",
    "    def __getitem__(self, idx):\n",
    "        # 配置获取每一张图片\n",
    "        img_name = self.img_path[idx]  # 获取数据集文件名称\n",
    "        img_item_path = os.path.join(\n",
    "            self.root_dir, self.label_dir, img_name)  # 获取完整数据集文件的路径\n",
    "        img = Image.open(img_item_path)  # 打开数据集文件\n",
    "        label = self.label_dir  # 获取数据集的标签名称\n",
    "        return img, label  # 返回打开的数据集文件,相对应的标签名称;\n",
    "\n",
    "    def __len__(self):\n",
    "        return len(self.img_path)     # 获取数据集的个数;\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-05-30T01:43:43.335073Z",
     "start_time": "2023-05-30T01:43:43.332829Z"
    }
   },
   "outputs": [],
   "source": [
    "root_dir = \"dataset/hymenoptera_data/train\"\n",
    "ants_label_dir = \"ants\"\n",
    "bees_label_dir = \"bees\"\n",
    "ants_dataset = MyData(root_dir, ants_label_dir)\n",
    "bees_dataset = MyData(root_dir, bees_label_dir)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "蚂蚁数据集路径： (<PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=500x375 at 0x7FD94B44CAF0>, 'ants')\n",
      "密码数据集路径：  (<PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=500x352 at 0x7FD94B4A1910>, 'bees')\n"
     ]
    }
   ],
   "source": [
    "print(\"蚂蚁数据集路径：\", ants_dataset[14])\n",
    "print(\"密码数据集路径： \", bees_dataset[1])\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-05-30T01:43:43.337725Z",
     "start_time": "2023-05-30T01:43:43.336004Z"
    }
   },
   "outputs": [],
   "source": [
    "train_dataset = ants_dataset+bees_dataset\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-05-30T01:43:43.341726Z",
     "start_time": "2023-05-30T01:43:43.338845Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "244"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "len(train_dataset)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 使用 TensorBoard\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "from torch.utils.tensorboard import SummaryWriter\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### TensorBoard 绘制表\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-05-30T01:48:45.931270Z",
     "start_time": "2023-05-30T01:48:45.865484Z"
    }
   },
   "outputs": [],
   "source": [
    "writer = SummaryWriter(\"logs/first\")\n",
    "\n",
    "# writer.add_image()\n",
    "for i in range(100):\n",
    "    # add_scalar(tag,data,epoch) tag:图标标题；data：y轴；epoch：x轴\n",
    "    writer.add_scalar(\"y=x\", i, i)\n",
    "writer.close()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "writer = SummaryWriter(\"logs/second\")\n",
    "\n",
    "# writer.add_image()\n",
    "for i in range(100):\n",
    "    # add_scalar(tag,data,epoch) tag:图标标题；data：y轴；epoch：x轴\n",
    "    writer.add_scalar(\"y=x*x\", i*i, i)\n",
    "writer.close()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "writer = SummaryWriter(\"logs/third\")\n",
    "\n",
    "# writer.add_image()\n",
    "for i in range(100):\n",
    "    # add_scalar(tag,data,epoch) tag:图标标题；data：y轴；epoch：x轴\n",
    "    writer.add_scalar(\"y=6*x\", 6*i, i)\n",
    "writer.close()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### TensorBoard 读取图片\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "writer = SummaryWriter(\"logs/dataset/image_ants\")\n",
    "j = 0\n",
    "for data in ants_dataset:\n",
    "    image, label = data\n",
    "    image_array = np.array(image)\n",
    "    j = j+1\n",
    "    writer.add_image(label, image_array, j, dataformats='HWC')\n",
    "writer.close()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "writer = SummaryWriter(\"logs/dataset/image_bees\")\n",
    "j = 0\n",
    "for data in bees_dataset:\n",
    "    image, label = data\n",
    "    image_array = np.array(image)\n",
    "    j = j+1\n",
    "    writer.add_image(label, image_array, j, dataformats='HWC')\n",
    "writer.close()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "123\n",
      "121\n"
     ]
    }
   ],
   "source": [
    "print(len(ants_dataset))\n",
    "print(len(bees_dataset))\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Transform 的使用\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [],
   "source": [
    "from torchvision import transforms\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "1. ToTensor 转换 tensor 类型\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "torch.Size([3, 375, 500])\n"
     ]
    }
   ],
   "source": [
    "img, label = ants_dataset[1]\n",
    "# 将图像转换为Tensor类型数据\n",
    "tensor = transforms.ToTensor()\n",
    "image_tensor = tensor(img)  # 参数类型：img或numpy\n",
    "print(image_tensor.shape)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [],
   "source": [
    "writer = SummaryWriter(\"logs/dataset/image_ants_tensor\")\n",
    "j = 0\n",
    "tensor = transforms.ToTensor()\n",
    "for data in ants_dataset:\n",
    "    image, label = data\n",
    "    image_tensor = tensor(image)\n",
    "    j = j+1\n",
    "    writer.add_image(\"ants_tensor\", image_tensor, j)  # 输入的类型为图片tensor类型\n",
    "writer.close()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "2. Normalize 标准化的使用\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 标准化操作\n",
    "transfer_norm = transforms.Normalize(\n",
    "    [0.5, 0.5, 0.5], [0.5, 0.5, 0.5])  # 平均值mean，标准差std\n",
    "# 输出计算公式：output[channel] = (input[channel] - mean[channel]) / std[channel]\n",
    "image_norm = transfer_norm(image_tensor)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [],
   "source": [
    "writer = SummaryWriter(\"logs/dataset/image_ants_normal\")\n",
    "j = 0\n",
    "mean = [3, 5, 6]  # 三个通道的平均值\n",
    "std = [6, 7, 8]  # 三个通道的标准差\n",
    "tensor = transforms.ToTensor()\n",
    "normal = transforms.Normalize(mean=mean, std=std)\n",
    "for data in ants_dataset:\n",
    "    image, label = data\n",
    "    image_tensor = tensor(image)  # 转化为tensor类型\n",
    "    image_normal = normal(image_tensor)  # 归一化\n",
    "    j = j+1\n",
    "    writer.add_image(\"ants_normal\", image_normal, j)  # 输入的类型为图片tensor类型\n",
    "writer.close()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "3. Resize 修改尺寸大小\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<PIL.Image.Image image mode=RGB size=512x512 at 0x7FD924568FD0>\n"
     ]
    }
   ],
   "source": [
    "# resize的使用\n",
    "resize_shape = (512, 512)\n",
    "resize = transforms.Resize(resize_shape)\n",
    "image_resize = resize(img)\n",
    "print(image_resize)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "4. Compose 的使用\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "torch.Size([3, 512, 682])\n"
     ]
    }
   ],
   "source": [
    "resize = transforms.Resize(512)  # 最小的边匹配这个512，其他的边可能放大或缩小\n",
    "compose = transforms.Compose([resize, tensor])  # 流水线工作,第一个输出必须是第二个的输入\n",
    "image_compose = compose(img)\n",
    "print(image_compose.shape)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "5. RandomCrop 的使用\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [],
   "source": [
    "randomcrop = transforms.RandomCrop(512)  # 一个数是裁剪为(512,512),俩个数就是正常的\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## TorchVision 的使用\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [],
   "source": [
    "import torchvision\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [],
   "source": [
    "\n",
    "\n",
    "tensor = torchvision.transforms.ToTensor()\n",
    "data_transform = torchvision.transforms.Compose([tensor])  # 数据预处理为tensor类型\n",
    "train_set = torchvision.datasets.CIFAR10(\n",
    "    root=\"./dataset\", train=True, transform=data_transform, download=False)\n",
    "test_set = torchvision.datasets.CIFAR10(\n",
    "    root=\"./dataset\", train=False, transform=data_transform, download=False)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "1. 使用 TensorBoard 显示数据集\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [],
   "source": [
    "writer = SummaryWriter(\"logs/dataset/CIFAR10_train\")\n",
    "i = 0\n",
    "for data in train_set:\n",
    "    img, label = data\n",
    "    i = i+1\n",
    "    writer.add_image(\"cifar10_train\", img, i)\n",
    "writer.close()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [],
   "source": [
    "writer = SummaryWriter(\"logs/dataset/CIFAR10_test\")\n",
    "i = 0\n",
    "for data in test_set:\n",
    "    img, label = data\n",
    "    i = i+1\n",
    "    writer.add_image(\"cifar10_test\", img, i)\n",
    "writer.close()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## DateLoader 的使用\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [],
   "source": [
    "from torch.utils.data import DataLoader\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [],
   "source": [
    "train_loader = DataLoader(dataset=train_set, batch_size=64,\n",
    "                          shuffle=True, num_workers=8, drop_last=False)\n",
    "test_loader = DataLoader(dataset=test_set, batch_size=64,\n",
    "                         shuffle=True, num_workers=8, drop_last=False)\n",
    "# shuffle设置上一把和这一把是否打乱，num_workers设置多进程，drop_last设置是否舍去多余的，batch_size表示将数据集打包64个为一组\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### tqdm 结合 DataLoader 显示进度\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "train epoch [1/20]: 100%|██████████| 782/782 [00:00<00:00, 918.19it/s] \n",
      "train epoch [2/20]: 100%|██████████| 782/782 [00:00<00:00, 1019.33it/s]\n",
      "train epoch [3/20]: 100%|██████████| 782/782 [00:00<00:00, 1030.15it/s]\n",
      "train epoch [4/20]: 100%|██████████| 782/782 [00:00<00:00, 1012.48it/s]\n",
      "train epoch [5/20]: 100%|██████████| 782/782 [00:00<00:00, 992.26it/s] \n",
      "train epoch [6/20]: 100%|██████████| 782/782 [00:00<00:00, 994.18it/s] \n",
      "train epoch [7/20]: 100%|██████████| 782/782 [00:00<00:00, 953.38it/s] \n",
      "train epoch [8/20]: 100%|██████████| 782/782 [00:00<00:00, 998.84it/s] \n",
      "train epoch [9/20]: 100%|██████████| 782/782 [00:00<00:00, 939.51it/s] \n",
      "train epoch [10/20]: 100%|██████████| 782/782 [00:00<00:00, 959.89it/s] \n",
      "train epoch [11/20]: 100%|██████████| 782/782 [00:00<00:00, 988.99it/s] \n",
      "train epoch [12/20]: 100%|██████████| 782/782 [00:00<00:00, 970.44it/s] \n",
      "train epoch [13/20]: 100%|██████████| 782/782 [00:00<00:00, 936.57it/s] \n",
      "train epoch [14/20]: 100%|██████████| 782/782 [00:00<00:00, 959.94it/s] \n",
      "train epoch [15/20]: 100%|██████████| 782/782 [00:00<00:00, 992.73it/s] \n",
      "train epoch [16/20]: 100%|██████████| 782/782 [00:00<00:00, 942.20it/s] \n",
      "train epoch [17/20]: 100%|██████████| 782/782 [00:00<00:00, 1013.16it/s]\n",
      "train epoch [18/20]: 100%|██████████| 782/782 [00:00<00:00, 937.60it/s] \n",
      "train epoch [19/20]: 100%|██████████| 782/782 [00:00<00:00, 992.47it/s] \n",
      "train epoch [20/20]: 100%|██████████| 782/782 [00:00<00:00, 1025.64it/s]\n"
     ]
    }
   ],
   "source": [
    "from tqdm import tqdm\n",
    "epochs = 20\n",
    "for epoch in range(epochs):\n",
    "    # 此处省略若干步骤\n",
    "    train_bar = tqdm(train_loader)   # 实时显示加载了多少数据\n",
    "    for step, data in enumerate(train_bar):\n",
    "        # 此处省略若干步骤\n",
    "        train_bar.desc = f\"train epoch [{epoch+1}/{epochs}]\"\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [],
   "source": [
    "writer = SummaryWriter(\"logs/dataset/CIFAR10_train_dataloader\")\n",
    "i = 0\n",
    "for data in train_loader:\n",
    "    imgs, labels = data\n",
    "    i = i+1\n",
    "    writer.add_images(\"cifar10_train_dataloader\", imgs, i)\n",
    "writer.close()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [],
   "source": [
    "writer = SummaryWriter(\"logs/dataset/CIFAR10_test_dataloader\")\n",
    "i = 0\n",
    "for data in test_loader:\n",
    "    imgs, labels = data\n",
    "    i = i+1\n",
    "    writer.add_images(\"cifar10_test_dataloader\", imgs, i)\n",
    "writer.close()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### DateLoader 实现验证码数据集\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "1. 自定义自己的数据集类\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Captcha_Data(Dataset):\n",
    "    def __init__(self, root_dir):\n",
    "        # 初始化路径配置\n",
    "        self.root_dir = root_dir\n",
    "        self.img_path = os.listdir(self.root_dir)\n",
    "\n",
    "    def __getitem__(self, index):\n",
    "        img_name = self.img_path[index]\n",
    "        img_item_path = os.path.join(self.root_dir, img_name)\n",
    "        img = Image.open(img_item_path)\n",
    "        label = img_name.split(\"_\")[0]\n",
    "        return img, label\n",
    "\n",
    "    def __len__(self):\n",
    "        return len(self.img_path)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [],
   "source": [
    "train_captcha = Captcha_Data(\"dataset/captcha/train\")\n",
    "img, label = train_captcha[0]\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 神经网络的基本骨架\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Contains 的使用\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "outputs": [],
   "source": [
    "import torch.nn as nn\n",
    "import torch.nn.functional as F\n",
    "\n",
    "\n",
    "class TestModel(nn.Module):\n",
    "    \"\"\"自定义模型\"\"\"\n",
    "\n",
    "    def __init__(self):\n",
    "        super().__init__()\n",
    "        self.conv1 = nn.Conv2d(1, 20, 5)\n",
    "        self.conv2 = nn.Conv2d(20, 20, 5)\n",
    "\n",
    "    def forward(self, x):\n",
    "        x = F.relu(self.conv1(x))\n",
    "        return F.relu(self.conv2(x))\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Convolution 的使用\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- torch.nn.functional 的卷积操作\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor([[[[ 1,  3,  4, 10,  8],\n",
      "          [ 5, 10, 12, 12,  6],\n",
      "          [ 7, 18, 16, 16,  8],\n",
      "          [11, 13,  9,  3,  4],\n",
      "          [14, 13,  9,  7,  4]]]])\n"
     ]
    }
   ],
   "source": [
    "input = torch.tensor([[1, 2, 0, 3, 1],\n",
    "                      [0, 1, 2, 3, 1],\n",
    "                      [1, 2, 1, 0, 0],\n",
    "                      [5, 2, 3, 1, 1],\n",
    "                      [2, 1, 0, 1, 1]])  # 卷积输入数据\n",
    "\n",
    "kernel = torch.tensor([[1, 2, 1],\n",
    "                       [0, 1, 0],\n",
    "                       [2, 1, 0]])  # 卷积核\n",
    "\n",
    "# resize为conv2d满足的input(minibatch,in_channels,H,W)\n",
    "input = torch.reshape(input, (1, 1, 5, 5))\n",
    "kernel = torch.reshape(kernel, (1, 1, 3, 3))\n",
    "\n",
    "# 卷积操作,stride=1表示卷积操作步长为1(横纵方向的步长),padding=1表示在输入数据进行填充,横纵方向都扩展一列或一行\n",
    "output = F.conv2d(input, kernel, stride=1, padding=1)\n",
    "print(output)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor([[[[10, 12],\n",
      "          [13,  3]]]])\n"
     ]
    }
   ],
   "source": [
    "output = F.conv2d(input, kernel, stride=2)  # 卷积操作,stride=2表示卷积操作步长为2(横纵方向的步长)\n",
    "print(output)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- torch.nn 的卷积操作\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {},
   "outputs": [],
   "source": [
    "output = nn.Conv2d(in_channels=1, out_channels=1, kernel_size=3, stride=1,)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {},
   "outputs": [],
   "source": [
    "class MyModel(nn.Module):\n",
    "    def __init__(self):\n",
    "        super(MyModel, self).__init__()\n",
    "        self.conv1 = nn.Conv2d(in_channels=3, out_channels=6,\n",
    "                               kernel_size=3, stride=1, padding=0)\n",
    "\n",
    "    def forward(self, x):\n",
    "        x = self.conv1(x)\n",
    "        return x\n",
    "\n",
    "\n",
    "HCode = MyModel()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {},
   "outputs": [],
   "source": [
    "writer = SummaryWriter(\"logs/dataset/CIFAR10_train_Conv2d\")\n",
    "i = 0\n",
    "for data in train_loader:\n",
    "    imgs, labels = data\n",
    "    output = HCode(imgs)\n",
    "    i = i+1\n",
    "    output = torch.reshape(output, (-1, 3, 30, 30))  # 修改channels为3\n",
    "    writer.add_images(\"input\", imgs, i)\n",
    "    writer.add_images(\"output\", output, i)\n",
    "writer.close()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Pooling layers 的使用\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([[[[2., 3.],\n",
       "          [5., 1.]]]])"
      ]
     },
     "execution_count": 41,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "input = torch.tensor([[1, 2, 0, 3, 1],\n",
    "                      [0, 1, 2, 3, 1],\n",
    "                      [1, 2, 1, 0, 0],\n",
    "                      [5, 2, 3, 1, 1],\n",
    "                      [2, 1, 0, 1, 1]], dtype=torch.float32)  # 卷积输入数据\n",
    "\n",
    "input = torch.reshape(input, (-1, 1, 5, 5))\n",
    "\n",
    "\n",
    "class MyModel(nn.Module):\n",
    "    def __init__(self):\n",
    "        super(MyModel, self).__init__()\n",
    "        self.maxpool1 = nn.MaxPool2d(\n",
    "            kernel_size=3, ceil_mode=True)  # ceil_mode=True表示不足时进行舍去\n",
    "\n",
    "    def forward(self, x):\n",
    "        x = self.maxpool1(x)\n",
    "        return x\n",
    "\n",
    "\n",
    "HCode = MyModel()\n",
    "HCode(input)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- Tensorboard 进行可视化\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {},
   "outputs": [],
   "source": [
    "writer = SummaryWriter(\"logs/dataset/CIFAR10_train_MaxPool\")\n",
    "i = 0\n",
    "for data in train_loader:\n",
    "    imgs, label = data\n",
    "    i = i+1\n",
    "    writer.add_images(\"input\", imgs, i)\n",
    "    output = HCode(imgs)\n",
    "    writer.add_images(\"output\", output, i)\n",
    "writer.close()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 非线性激活的使用\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "metadata": {},
   "outputs": [],
   "source": [
    "class MyModel(nn.Module):\n",
    "\n",
    "    def __init__(self):\n",
    "        super(MyModel, self).__init__()\n",
    "        self.relu1 = nn.ReLU()\n",
    "\n",
    "    def forward(self, x):  # 前向传播\n",
    "        x = self.relu1(x)\n",
    "        return x\n",
    "\n",
    "\n",
    "HCode = MyModel()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {},
   "outputs": [],
   "source": [
    "writer = SummaryWriter(\"logs/dataset/CIFAR10_train_ReLU\")\n",
    "i = 0\n",
    "for data in train_loader:\n",
    "    imgs, label = data\n",
    "    i = i+1\n",
    "    writer.add_images(\"input\", imgs, i)\n",
    "    output = HCode(imgs)\n",
    "    writer.add_images(\"output\", output, i)\n",
    "\n",
    "writer.close()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 神经网络实战\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 创建自己的网络\n",
    "class MyModel(nn.Module):\n",
    "    def __init__(self):\n",
    "        super(MyModel, self).__init__()\n",
    "        # # 卷积层1\n",
    "        # self.conv1 = nn.Conv2d(3, 32,  stride=1, kernel_size=5, padding=2)\n",
    "        # # 池化层1\n",
    "        # self.maxpool1 = nn.MaxPool2d(kernel_size=2)\n",
    "        # self.conv2 = nn.Conv2d(32, 32, kernel_size=5, stride=1, padding=2)\n",
    "        # self.maxpool2 = nn.MaxPool2d(kernel_size=2)\n",
    "        # self.conv3 = nn.Conv2d(32, 64, kernel_size=5, stride=1, padding=2)\n",
    "        # self.maxpool3 = nn.MaxPool2d(kernel_size=2)\n",
    "        # self.flatten = nn.Flatten()\n",
    "        # self.linear1 = nn.Linear(1024, 64)\n",
    "        # self.linear2 = nn.Linear(64, 10)\n",
    "\n",
    "        # Sequential进行简化\n",
    "        self.model1 = nn.Sequential(\n",
    "            nn.Conv2d(3, 32,  stride=1, kernel_size=5, padding=2),\n",
    "            nn.MaxPool2d(kernel_size=2),\n",
    "            nn.Conv2d(32, 32, kernel_size=5, stride=1, padding=2),\n",
    "            nn.MaxPool2d(kernel_size=2),\n",
    "            nn.Conv2d(32, 64, kernel_size=5, stride=1, padding=2),\n",
    "            nn.MaxPool2d(kernel_size=2),\n",
    "            nn.Flatten(),\n",
    "            nn.Linear(1024, 64),\n",
    "            nn.Linear(64, 10),\n",
    "        )\n",
    "\n",
    "    def forward(self, x):\n",
    "        # x = self.conv1(x)\n",
    "        # x = self.maxpool1(x)\n",
    "        # x = self.conv2(x)\n",
    "        # x = self.maxpool2(x)\n",
    "        # x = self.conv3(x)\n",
    "        # x = self.maxpool3(x)\n",
    "        # x = self.flatten(x)\n",
    "        # x = self.linear1(x)\n",
    "        # x = self.linear2(x)\n",
    "        x = self.model1(x)\n",
    "        return x\n",
    "\n",
    "\n",
    "HCode = MyModel()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "torch.Size([64, 10])\n"
     ]
    }
   ],
   "source": [
    "input = torch.ones((64, 3, 32, 32))\n",
    "output = HCode(input)\n",
    "print(output.shape)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Loss 的使用\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor(2.)"
      ]
     },
     "execution_count": 47,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "inputs = torch.tensor([1, 2, 3], dtype=torch.float32)\n",
    "targets = torch.tensor([1, 2, 5], dtype=torch.float32)\n",
    "\n",
    "inputs = torch.reshape(inputs, (1, 1, 1, 3))\n",
    "targets = torch.reshape(targets, (1, 1, 1, 3))\n",
    "\n",
    "loss = nn.L1Loss(reduction='sum')  # 第一范式损失\n",
    "result = loss(inputs, targets)\n",
    "result\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.18"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {
    "height": "calc(100% - 180px)",
    "left": "10px",
    "top": "150px",
    "width": "288px"
   },
   "toc_section_display": true,
   "toc_window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
